import Flutter
import UIKit
import AMapSearchKit

public class SwiftMhFlutterAmapSearchPlugin: NSObject, FlutterPlugin{
    
    private var _searchApi:AMapSearchAPI?
    private var searchApi : AMapSearchAPI {
        get {
            if _searchApi == nil {
                let api = AMapSearchAPI.init()
                api?.delegate = self
                _searchApi = api
            }
            return _searchApi!
        }
        set {
            _searchApi = newValue
        }
    }
    private var _channel : FlutterMethodChannel?
    
    
  public static func register(with registrar: FlutterPluginRegistrar) {
    
    let channel = FlutterMethodChannel(name: "mh_flutter_amap_search", binaryMessenger: registrar.messenger())
    let instance = SwiftMhFlutterAmapSearchPlugin()
    instance._channel = channel
    registrar.addMethodCallDelegate(instance, channel: channel)
    
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    
    let args = call.arguments as? Dictionary<String, Any>
    
    if call.method == "getPlatformVersion" {
        result("iOS " + UIDevice.current.systemVersion)
    }else if call.method == "setApiKey" {
        let iosKey = args?["iosKey"] as? String ?? ""
        AMapServices.shared().apiKey = iosKey
    }else if call.method == "searchKeyword" {
        let request = AMapPOIKeywordsSearchRequest()
        request.city = args?["city"] as? String ?? ""
        request.keywords = args?["keyword"] as? String ?? ""
        request.page = args?["page"] as? Int ?? 1
        request.offset = args?["pageSize"] as? Int ?? 20
        searchApi.aMapPOIKeywordsSearch(request)
    }else if call.method == "searchAround" {
        let request = AMapPOIAroundSearchRequest()
        request.city = args?["city"] as? String ?? ""
        request.keywords = args?["keyword"] as? String ?? ""
        request.page = args?["page"] as? Int ?? 1
        request.offset = args?["pageSize"] as? Int ?? 20
        request.radius = args?["radius"] as? Int ?? 20
        request.types = args?["type"] as? String ?? ""
        
        let latitude = args?["latitude"] as? CGFloat ?? 0
        let longitude = args?["longitude"] as? CGFloat ?? 0
        
        request.location = AMapGeoPoint.location(withLatitude: latitude, longitude: longitude)
        
        searchApi.aMapPOIAroundSearch(request)
        
    }else if call.method == "searchPoiId" {
        
        let poiIdSearch = AMapPOIIDSearchRequest()
        poiIdSearch.uid = (call.arguments as? Dictionary)?["uid"]
        searchApi.aMapPOIIDSearch(poiIdSearch)
    }else if call.method == "searchGeocode" {
        let request = AMapGeocodeSearchRequest()
        request.city = args?["city"] as? String ?? ""
        request.address = args?["address"] as? String ?? ""
        searchApi.aMapGeocodeSearch(request)
    }else if call.method == "searchReGeocode" {
        let request = AMapReGeocodeSearchRequest()
        request.radius = args?["radius"] as? Int ?? 200
        
        let latitude = args?["latitude"] as? CGFloat ?? 0
        let longitude = args?["longitude"] as? CGFloat ?? 0
        request.location = AMapGeoPoint.location(withLatitude: latitude, longitude: longitude)
        
        searchApi.aMapReGoecodeSearch(request)
    }else if call.method == "fetchInputTips" {
        let request = AMapInputTipsSearchRequest()
        request.keywords = (call.arguments as? Dictionary)?["keyword"]
        request.city = args?["city"] as? String ?? ""
        searchApi.aMapInputTipsSearch(request)
    }else if call.method == "distanceSearch" {
        let request = AMapDistanceSearchRequest()
        let originMaps = args!["origins"] as? Array<Dictionary<String,CGFloat>> ?? []
        let type = args?["type"] as? Int
        let destination = args?["destination"] as! Dictionary<String,CGFloat>
        
        let origins = originMaps.map { item  in
            
            return AMapGeoPoint.location(withLatitude: item["latitude"] ?? 0, longitude: item["longitude"] ?? 0)!
        }
        
        request.origins = origins
        request.destination = AMapGeoPoint.location(withLatitude: destination["latitude"] ?? 0, longitude: destination["longitude"] ?? 0)
        request.type = AMapDistanceSearchType(rawValue: type ?? 0)!
        searchApi.aMapDistanceSearch(request)
    }else{
        result(FlutterMethodNotImplemented)
    }
  }
}

extension SwiftMhFlutterAmapSearchPlugin :AMapSearchDelegate {
    
    public func onDistanceSearchDone(_ request: AMapDistanceSearchRequest!, response: AMapDistanceSearchResponse!) {
        let results = response.results
        let res = results?.map({ item  in
            item.toJson()
        })
        _channel?.invokeMethod("onDistanceSearchDone", arguments: [
            "requestType": "distanceSearch",
            "distanceList":res ?? []
        ])
    }
    
    public func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
        print(error ?? "unkown err");
        var requestType: String = "";
        let searchRequset = request as! AMapSearchObject
        let err = error as NSError
        if searchRequset.isKind(of: AMapPOIKeywordsSearchRequest.self) {
            requestType = "keySearch"
        }else if searchRequset.isKind(of: AMapPOIAroundSearchRequest.self){
            requestType = "aroundSearch"
        }else if searchRequset.isKind(of: AMapPOIIDSearchRequest.self){
            requestType = "idSearch"
        }else if(searchRequset.isKind(of: AMapGeocodeSearchRequest.self)){
            requestType = "geoSearch"
        }else if(searchRequset.isKind(of: AMapReGeocodeSearchRequest.self)){
                requestType = "reGeoSearch"
        }else if(searchRequset.isKind(of: AMapInputTipsSearchRequest.self)){
            requestType = "inputTipsSearch"
        }else if(searchRequset.isKind(of: AMapDistanceSearchRequest.self)){
            requestType = "distanceSearch"
        }
        
        _channel?.invokeMethod("onAMapSearchRequest_didFailWithError", arguments: ["requestType":requestType,"errMessage":err.userInfo["NSLocalizedDescription"]])
    }
    public func onPOISearchDone(_ request: AMapPOISearchBaseRequest!, response: AMapPOISearchResponse!) {
        
        let requestType = request.isKind(of: AMapPOIKeywordsSearchRequest.self) ? "keySearch" : request.isKind(of: AMapPOIIDSearchRequest.self) ? "idSearch" : "aroundSearch";
        
        var resultArr : [[String:Any]] = []
        for poi in response.pois {
            let poiItem = poi.toJson()
            resultArr.append(poiItem)
        }
        _channel?.invokeMethod("onPOISearchDone", arguments: [
            "requestType": requestType,
            "count": NSNumber(value: response.count),
            "pois":resultArr
        ])
    }
//    public func onNearbySearchDone(_ request: AMapNearbySearchRequest!, response: AMapNearbySearchResponse!) {
//
//    }
    public func onGeocodeSearchDone(_ request: AMapGeocodeSearchRequest!, response: AMapGeocodeSearchResponse!) {
        
        let geocodes = response.geocodes ?? []
        let resultArr = geocodes.map { item  in
            item.toJson()
        }
        
        _channel?.invokeMethod("onGeocodeSearchDone", arguments: [
            "requestType": "geoSearch",
            "count": NSNumber(value: response.count),
            "geocodes":resultArr
        ])
    }
    public func onReGeocodeSearchDone(_ request: AMapReGeocodeSearchRequest!, response: AMapReGeocodeSearchResponse!) {
        
        var arguments: [String:Any] = ["requestType": "reGeoSearch"]
        let item = response.regeocode.toJson()
        arguments["regeocode"] = item
        _channel?.invokeMethod("onReGeocodeSearchDone", arguments: arguments)
    }
    public func onInputTipsSearchDone(_ request: AMapInputTipsSearchRequest!, response: AMapInputTipsSearchResponse!) {

        var tips = response.tips ?? []
        tips = tips.filter({ item in
            item.location != nil
        })
        let resultArr = tips.map { item  in
            return item.toJson()
        }
        
        _channel?.invokeMethod("onInputTipsSearchDone", arguments: [
            "requestType": "inputTipsSearch",
            "count": NSNumber(value: response.count),
            "tips":resultArr
        ])
    }
}


